﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Threading;
using Super.Infrastructure;
using Super.Entities;
using System.ComponentModel;

namespace Super.DomainService
{
    /// <summary> 数据同步元素
    /// </summary>
    public class DataSyncElement
    {
        public int ID;
        public DateTime NeedSyncTime;
    }

    /// <summary> 数据预处理信息
    /// </summary>
    public class DataSyncPretreatInfo
    {
        public Type DataType;

        private int pretreatCount;

        public int PretreatCount
        {
            get { return pretreatCount; }
            set
            {
                pretreatCount = value;
            }
        }

        private int waitCount;
        public int WaitCount
        {
            get { return waitCount; }
            set
            {
                waitCount = value;
            }
        }
    }

    /// <summary> 数据同步 状态信息
    /// </summary>
    public class DataSyncStateInfo
    {
        public event Action StateChanger;

        private string nowProcess;

        /// <summary> 当前处理类型
        /// </summary>
        public string NowProcess
        {
            get { return nowProcess; }
            set
            {
                if (nowProcess != value)
                {
                    nowProcess = value;
                    if (StateChanger != null)
                    {
                        StateChanger.Invoke();
                    }
                }
            }
        }

        /// <summary> 预处理信息集合
        /// </summary>
        public List<DataSyncPretreatInfo> PretreatInfoList;
    }

    /// <summary> 数据同步规则
    /// </summary>
    public class DataSyncRule
    {
        /// <summary> 预处理间隔
        /// </summary>
        public TimeSpan PretreatSpan;

        /// <summary> 最后预处理时间
        /// </summary>
        public DateTime LastPretreatDateTime;

        /// <summary> 要处理的数据类型 
        /// </summary>
        public Type DataType;

        /// <summary> 预处理数据
        /// </summary>
        public List<DataSyncElement> PretreatData;

        /// <summary> 获取预处理数据
        /// </summary>
        public Func<List<DataSyncElement>> GetPretreatData;

        /// <summary> 数据需要更改后 回调函数
        /// </summary>
        public Action<object> CallBack;

        /// <summary> 获取预处理数据.
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        public int RefreshPretreatData()
        {
            PretreatData = GetPretreatData();
            return PretreatData.Count;
        }
    }

    /// <summary> 数据同步类
    /// </summary>
    public class DataSync
    {
        public DataSync()
        {
            Rules = new List<DataSyncRule>();
            StateInfo = new DataSyncStateInfo();
            StateInfo.StateChanger += new Action(StateInfo_StateChanger);
            StateInfo.PretreatInfoList = new List<DataSyncPretreatInfo>();
        }

        public event Action StateChanger;

        void StateInfo_StateChanger()
        {
            if (StateChanger != null)
            {
                StateChanger();
            }
        }

        /// <summary> 规则集合
        /// </summary>
        public List<DataSyncRule> Rules { get; set; }

        /// <summary> 预处理信息
        /// </summary>
        public DataSyncStateInfo StateInfo { get; set; }


        /// <summary> 添加数据同步定时器规则
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
        public void AddRuleOfTimer<TEntity>(TimeSpan pretreatSpan, Func<IEnumerable<DataSyncElement>> getPretereatData, Func<TEntity, object> callBack)
        {
            var v = new DataSyncRule()
            {
                GetPretreatData = () => { var l = getPretereatData.Invoke().ToList(); l.OrderBy(j => j.NeedSyncTime); return l; },
                CallBack = j => callBack.Invoke((TEntity)j),
                LastPretreatDateTime = new DateTime(),
                DataType = typeof(TEntity),
                PretreatSpan = pretreatSpan
            };

            Rules.Add(v);
        }


        /// <summary> 添加数据同步规则
        /// </summary>
        /// <typeparam name="TEntity">数据实体</typeparam>
        /// <param name="waitSpan">数据过期时间</param>
        /// <param name="pretreatSpan">预处理间隔(必须小于数据过期时间)</param>
        /// <param name="getPretereatData">数据预处理查询委托</param>
        /// <param name="updateCallBack">数据更新委托</param>
        public void AddRuleOfTimer<TEntity>
            (
                TimeSpan waitSpan,
                TimeSpan pretreatSpan,
                Func<DateTime, IQueryable<object>> getPretereatData,
                Action<TEntity> updateCallBack
            )
        {

            var v = new DataSyncRule()
            {
                PretreatSpan = pretreatSpan,
                LastPretreatDateTime = new DateTime(),
                PretreatData = null,
                DataType = typeof(TEntity),
                CallBack = j => updateCallBack.Invoke((TEntity)j),
                GetPretreatData = () =>
                {
                    var d = DateTime.Now;
                    //当前时间 + 预处理间隔 = 预处理结束时间.
                    //预处理结束时间 - 数据有效期 = 此次预处理需要处理的最大时间.
                    d.Add(pretreatSpan).AddTicks(0 - waitSpan.Ticks);
                    var ds = getPretereatData.Invoke(d);
                    var dd = ds.ToList();
                    return dd.Select
                        (
                            j => new DataSyncElement()
                            {
                                ID = (int)(j.GetType().GetProperty("ID").GetValue(j, null)),
                                NeedSyncTime = ((DateTime)(j.GetType().GetProperty("Date").GetValue(j, null))).Add(waitSpan)
                            }
                        ).ToList();
                }
            };


            StateInfo.PretreatInfoList.Add(new DataSyncPretreatInfo() { DataType = v.DataType });
            Rules.Add(v);
        }

        /// <summary> 开启后台处理程序.
        /// </summary>
        public void BeginRun()
        {
            var th = new Thread(ThRun) {IsBackground = true};

            th.Start();
        }

        /// <summary> 同步线程
        /// </summary>
        public void ThRun()
        {
            while (true)
            {
                StateInfo.NowProcess = "空闲";
                Thread.Sleep(1000);

                //对需要预处理的规则进行预处理
                foreach (var item in Rules)
                {
                    //判断是否需要预处理
                    var si = StateInfo.PretreatInfoList.First(j => j.DataType == item.DataType);
                    if (item.LastPretreatDateTime.Add(item.PretreatSpan) < DateTime.Now)
                    {
                        //执行预处理                        
                        StateInfo.NowProcess = "预处理 " + item.DataType.Name;
                        si.PretreatCount += item.RefreshPretreatData();
                        item.LastPretreatDateTime = DateTime.Now;
                    }

                    //判断是否有需要处理数据 
                    while (item.PretreatData.Count > 0 && item.PretreatData.First().NeedSyncTime < DateTime.Now)
                    {
                        var v = item.PretreatData.First();
                        StateInfo.NowProcess = "更新数据 " + item.DataType.Name + " id: " + v.ID;
                        item.PretreatData.RemoveAt(0);

                        //using (var sc = new StoreContext())
                        //{
                        //    var dt = sc.Set(item.DataType).Find(v.ID);
                        //    item.CallBack(dt);
                        //    sc.SaveChanges();
                        //}

                        si.WaitCount = item.PretreatData.Count;
                    }
                }
            }
        }
    }
}
